/** @brief Fichier déclarant une classe de gestion de balise XML.
 *
 * Ce fichier contient la déclaration d'une classe permettant de gérer des balises XML.
 *
 * @file ElementDOM.cpp
 * @author Johan "Solo" Luisier
 * @date Septembre 2009
 */
#include "ElementDOM.hpp"

#include "Utils/ATL.hpp"

#include <algorithm>

using namespace std;

const string ElementDOM::null("");

DebugLevelType ElementDOM::interne( BLANK );

ElementDOM::ElementDOM(const string& bal, const unsigned int& niv,
		       const string& data, const unsigned int& numero,
		       const ElementDOM* parent, const bool& aDonnees)
  : Balise( bal ), Niveau( niv ), Donnees( data ), Numero( numero ),
    Parent( parent ), contientDonnees( aDonnees ), nbrAttributs( 0 )
{}

ElementDOM::ElementDOM(const ElementDOM& dom)
  : Balise( dom.balise() ), Niveau( dom.niveau() ), Donnees( dom.donnees() ),
    Numero( dom.numero() ), Parent( dom.parent() ),
    contientDonnees( dom.aDonnees() ), nbrAttributs( dom.nbrAttributs )
    
{
  Attributs = dom.Attributs;
}

ElementDOM::~ElementDOM()
{}

void ElementDOM::setBalise(const string& bal)
{
  Balise = bal;
}

void ElementDOM::setNiveau(const unsigned int& lvl)
{
  Niveau = lvl;
}

void ElementDOM::setDonnees(const string& data)
{
  Donnees = data;
}

void ElementDOM::setNumero(const unsigned int& numero)
{
  Numero = numero;
}

void ElementDOM::setParent(const ElementDOM*& parent)
{
  Parent = parent;
}

void ElementDOM::ajoutEnfant(/*const*/ ElementDOM*& enfant)
{
  Enfants.push_back( enfant );

  vector< const ElementDOM* >::iterator it, fin( Enfants.end() );

  sort( Enfants.begin(), fin );

  it = unique( Enfants.begin(), fin );

  Enfants.erase( it, fin );
}

void ElementDOM::setADonnees(const bool& aDonnees)
{
  contientDonnees = aDonnees;
}

void ElementDOM::ajoutAttribut(const string& attrib, const string& val)
{
  Debug::empileNiveau( &interne );
  //DebugLevelType etat_precedent( dout.getLevel() );
  //dout.setLevel( interne );
  func() << "ElementDOM::ajoutAttribut -> début" << endreq;

  if ( attrib[0] == ' ' || attrib.empty() || attrib[0] == 0 )
    {
      func() << "ElementDOM::ajoutAttribut -> fin" << endreq;
      Debug::depileNiveau();//dout.setLevel( etat_precedent );
      return;
    }
  else if ( Attributs.find( attrib ) == Attributs.end() )
    {
      debug() << "Ajout attribut " << attrib << ", valeur " << val << endreq;
      nbrAttributs++;
      Attributs[ attrib ] = val;
    }

  func() << "ElementDOM::ajoutAttribut -> fin" << endreq;
  Debug::depileNiveau();//dout.setLevel( etat_precedent );
}

const string& ElementDOM::balise() const
{
  return Balise;
}

const unsigned int& ElementDOM::niveau() const
{
  return Niveau;
}

const string& ElementDOM::donnees() const
{
  return Donnees;
}

const unsigned int& ElementDOM::numero() const
{
  return Numero;
}

const ElementDOM* ElementDOM::parent() const
{
  return Parent;
}

const vector< const ElementDOM* >* ElementDOM::enfants() const
{
  return &Enfants;
}

const bool& ElementDOM::aDonnees() const
{
  return contientDonnees;
}

bool ElementDOM::aAttributs() const
{
  return ( Attributs.begin() != Attributs.end() );
}

vector< string > ElementDOM::attributs() const
{
  // map< string, string >::const_iterator It, Begin( Attributs.begin() ),
  //   End( Attributs.end() );

  vector< string > retour;

  // for (It = Begin; It != End; It++)
  //   retour . push_back( It -> first );

  ExtraireClef< string, string > extraitStr;

  retour.resize( Attributs.size() );

  transform( Attributs.begin(), Attributs.end(), retour.begin(),
	     extraitStr );

  return retour;
}

const string& ElementDOM::attribut(const string& attrib) const
{
  if ( Attributs.find( attrib ) == Attributs.end() )
    return null;
  else
    return Attributs.find( attrib ) -> second;
}

const string& ElementDOM::attribut(const unsigned int& num) const
{
  map< string, string >::const_iterator It, Begin( Attributs.begin() ),
    End( Attributs.end() );

  unsigned int i(0);

  for (It = Begin; It != End; It++, i++)
    {
      if ( i == num )
	return It -> second;
    }
  
  return null;
}

ElementDOM& ElementDOM::operator=(const ElementDOM& dom)
{
  if ( this != &dom )
    {
      Balise          = dom.balise();
      Niveau          = dom.niveau();
      Donnees         = dom.donnees();
      Numero          = dom.numero();
      Attributs       = dom.Attributs;
      Parent          = dom.parent();
      contientDonnees = dom.aDonnees();
      nbrAttributs    = dom.nbrAttributs;
    }
  return *this;
}

ostream& ElementDOM::afficheAttributs(ostream& os) const
{
  map< string, string >::const_iterator It, Begin( Attributs.begin() ),
    End( Attributs.end() );

  unsigned int i(0);

  for (It = Begin; It != End; It++, i++)
    {
      os << It -> first << " = " << It -> second;
      if ( i != nbrAttributs - 1 )
	os << ", ";
    }
  return os;
}

void ElementDOM::setLevel(const DebugLevelType& lvl)
{
  interne = lvl;
}
